package com.yan.test.work.testphoto;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.MediaRecorder;
import android.media.MediaScannerConnection;
import android.os.Bundle;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
import android.util.Size;
import android.view.LayoutInflater;
import android.view.OrientationEventListener;
import android.view.SoundEffectConstants;
import android.view.Surface;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraInfoUnavailableException;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.FocusMeteringAction;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.Preview;
import androidx.camera.core.VideoCapture;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;

import com.google.common.util.concurrent.ListenableFuture;
import com.yan.test.work.testphoto.databinding.ActivityLayoutCaptureBinding;
import com.yan.test.work.testphoto.view.RecordView;

import java.io.File;
import java.util.concurrent.ExecutionException;


public class CaptureActivity extends AppCompatActivity {
    public static final int REQ_CAPTURE = 10001;
    private ActivityLayoutCaptureBinding mBinding;
    private static final int PERMISSION_CODE = 1000;
    private String TAG = "CaptureActivity";

    private int rotation = Surface.ROTATION_0;
    private Size resolution = new Size(1280, 720);
    private Preview preview;
    private ImageCapture imageCapture;
    @SuppressLint("RestrictedApi")
    private VideoCapture videoCapture;

    private boolean takingPicture;
    private String outputFilePath;
    private CameraSelector cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;

    public static final String RESULT_FILE_PATH = "file_path";
    public static final String RESULT_FILE_TYPE = "file_type";

    private ProcessCameraProvider cameraProvider;
    private PreviewView previewView;
    private ImageView changeBtn;
    private RecordView recordView;
    private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
    private File outputFile;
    private String cameraType = null;
    public static final String CAMERA_TYPE_BACK = "camera_type_back";
    public static final String CAMERA_TYPE_FRONT = "camera_type_front";
    private Bundle extras;
    private boolean canVideo;
    private OrientationEventListener orientationEventListener;
    private Camera camera;

    public static void startActivityForResult(Activity activity , File outputFilde){
        startActivityForResult(activity , outputFilde , true , CAMERA_TYPE_BACK);
    }

    public static void startActivityForResult(Activity activity , File outputFilde , boolean canVideo , String cameraType) {
        Intent intent = new Intent(activity, CaptureActivity.class);
        Bundle bundle = new Bundle();
        try {
            bundle.putSerializable("OUTPUT" , outputFilde);
        } catch (Exception e) {
            e.printStackTrace();
        }
        bundle.putBoolean("CAN_VIDEO" , canVideo);
        bundle.putString("CAMERA_TYPE" , cameraType);
        intent.putExtras(bundle);
        activity.startActivityForResult(intent, REQ_CAPTURE);
    }

    public static void startActivityForResult(Fragment fragment , File outputFilde ){
        startActivityForResult(fragment , outputFilde , true , CAMERA_TYPE_BACK);
    }

    public static void startActivityForResult(Fragment fragment , File outputFilde , boolean canVideo ,String cameraType) {

        ListenableFuture<ProcessCameraProvider> instance = ProcessCameraProvider.getInstance(fragment.getContext());
        instance.addListener( ()->{
            try {
                ProcessCameraProvider provider = instance.get();
                boolean hadFront = provider.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA);
                boolean hadBack = provider.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA);
                if(hadFront  &&  hadBack){
                    Intent intent = new Intent(fragment.getContext(), CaptureActivity.class);
                    Bundle bundle = new Bundle();
                    try {
                        bundle.putSerializable("OUTPUT" , outputFilde);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    bundle.putBoolean("CAN_VIDEO" , canVideo);
                    bundle.putString("CAMERA_TYPE" , cameraType);
                    intent.putExtras(bundle);
                    fragment.startActivityForResult(intent, REQ_CAPTURE);
                }

            } catch (ExecutionException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (CameraInfoUnavailableException e) {
                e.printStackTrace();
            }

        } , ContextCompat.getMainExecutor(fragment.getContext()));


    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mBinding = ActivityLayoutCaptureBinding.inflate(LayoutInflater.from(this));
        ActivityUtil.makeStatusBarTransparent(this);
        setContentView(mBinding.getRoot());
        initView();
        initData();
        initCapture();
        initListener();
        startCamera();

        initRotation();

    }

    @SuppressLint("RestrictedApi")
    private void initCapture() {

        preview = new Preview.Builder()
                .setTargetRotation(rotation)
                .setDefaultResolution(resolution)
                .build();
        //照片Capture
        imageCapture = new ImageCapture.Builder()
                .setTargetRotation(rotation)
                .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                .setDefaultResolution(resolution)
                .setFlashMode(ImageCapture.FLASH_MODE_AUTO)
                .build();

        videoCapture = new VideoCapture.Builder()
                .setTargetRotation(rotation)
                .setVideoFrameRate(30)
                .setDefaultResolution(resolution)
                .setAudioRecordSource(MediaRecorder.AudioSource.MIC)
                .build();
    }


    @Override
    protected void onStart() {
        super.onStart();
        orientationEventListener.enable();
    }

    @Override
    protected void onStop() {
        orientationEventListener.disable();
        super.onStop();
    }

    @SuppressLint("RestrictedApi")
    private void initRotation() {
        orientationEventListener = new OrientationEventListener(AppGlobals.getApplication()){
            @SuppressLint("UnsafeOptInUsageError")
            @Override
            public void onOrientationChanged(int orientation) {
                if (orientation == ORIENTATION_UNKNOWN) {
                    return;
                }

                if(orientation>=45 && orientation < 135){
                    rotation = Surface.ROTATION_270;
                }else if(orientation >= 135 && orientation < 225){
                    rotation = Surface.ROTATION_180;
                }else if(orientation >= 225 && orientation < 315){
                    rotation = Surface.ROTATION_90;
                }else {
                    rotation = Surface.ROTATION_0;
                }
                preview.setTargetRotation(rotation);
                imageCapture.setTargetRotation(rotation);
                videoCapture.setTargetRotation(rotation);
            }
        };
    }

    private void initData() {
        extras = getIntent().getExtras();
        if(extras!=null){
            outputFile = (File) extras.getSerializable("OUTPUT");
            canVideo = extras.getBoolean("CAN_VIDEO" , true);
            cameraType = extras.getString("CAMERA_TYPE", CAMERA_TYPE_BACK);
        }else{
            canVideo = true;
            cameraType = CAMERA_TYPE_BACK;
        }

        //如果没有录音权限则只能拍照 不允许录像
        if(ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED){
            canVideo = false;
        }

        if(TextUtils.equals(cameraType , CAMERA_TYPE_BACK )){
            cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;
        }else if(TextUtils.equals(cameraType , CAMERA_TYPE_FRONT )){
            cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA;
        }

        recordView.setVideoRecord(canVideo);

    }

    private void startCamera() {
        cameraProviderFuture = ProcessCameraProvider.getInstance(this);
        cameraProviderFuture.addListener(new Runnable() {
            @Override
            public void run() {
                try {
                    cameraProvider = cameraProviderFuture.get();
                    bindCameraUseCases();
                } catch (ExecutionException e) {
                    showErrorToast("CAPTURE_ERROR");
                    e.printStackTrace();
                    finish();
                } catch (InterruptedException e) {
                    showErrorToast("CAPTURE_ERROR");
                    e.printStackTrace();
                    finish();
                }
            }
        } , ContextCompat.getMainExecutor(this));
    }

    private void initListener() {
        //点击照相按钮
        recordView.setOnRecordListener(new RecordView.onRecordListener() {
            @Override
            public void onClick() {
                takingPicture = true;
                takePicture();
            }

            @Override
            public void onLongClick() {
                takingPicture = false;
                startRecording();
            }

            @Override
            public void onFinish() {
                stopRecording();
            }
        });

        changeBtn.setOnClickListener(v -> {
            if(cameraSelector == CameraSelector.DEFAULT_BACK_CAMERA){
                cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA;
            }else{
                cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;
            }
            bindCameraUseCases();
        });

        previewView.setOnTouchListener((v, event) -> {
            FocusMeteringAction action = new FocusMeteringAction.Builder(
                    previewView.getMeteringPointFactory().createPoint(event.getX(), event.getY())
            ).build();
            showTapView((int)(event.getX()) , (int)(event.getY()));
            if(camera!=null){
                camera.getCameraControl().startFocusAndMetering(action);
            }
            return true;
        });

    }

    private void showTapView( int x, int y ) {
        PopupWindow popupWindow = new PopupWindow( 100, 100 );

        ImageView imageView = new ImageView(this);
        imageView.setImageResource(R.mipmap.ic_focus_view);

        popupWindow.setContentView(imageView);
        popupWindow.showAsDropDown(previewView, x-50,y+50);
        previewView.postDelayed(()->popupWindow.dismiss(), 600);
        previewView.playSoundEffect(SoundEffectConstants.CLICK);

    }

    private void takePicture() {
        if(outputFile==null){
            outputFile = new File(getExternalCacheDir(), System.currentTimeMillis()+".png");
        }
        Log.e(TAG, "照片文件: "+ outputFile.getAbsolutePath());
        ImageCapture.OutputFileOptions.Builder builder = new ImageCapture.OutputFileOptions.Builder(outputFile);
        ImageCapture.OutputFileOptions outputOptions = builder.build();
        imageCapture.takePicture(outputOptions,
                ContextCompat.getMainExecutor(this),
                new ImageCapture.OnImageSavedCallback() {
                    @Override
                    public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
                        Log.e(TAG, "success: IMAGE_SAVE_SUCCESS");
                        onFileSaved(outputFile);
                    }

                    @Override
                    public void onError(@NonNull ImageCaptureException exception) {
                        Log.e(TAG, "onError: IMAGE_SAVE_ERROR");
                    }
                }
        );
    }

    @SuppressLint("RestrictedApi")
    private void startRecording() {
        if(outputFile==null){
            outputFile = new File(getExternalCacheDir(), System.currentTimeMillis()+".mp4");
        }
        Log.e(TAG, "视频文件: "+ outputFile.getAbsolutePath());
        VideoCapture.OutputFileOptions.Builder builder = new VideoCapture.OutputFileOptions.Builder(outputFile);
        VideoCapture.OutputFileOptions outputOptions = builder.build();
        videoCapture.startRecording(outputOptions,
                ContextCompat.getMainExecutor(this),
                new VideoCapture.OnVideoSavedCallback() {
                    @Override
                    public void onVideoSaved(@NonNull VideoCapture.OutputFileResults outputFileResults) {
                        Log.e(TAG, "onError: VIDEO_SAVE_SUCCESS");
                        onFileSaved(outputFile);
                    }

                    @Override
                    public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) {
                        Log.e(TAG, "onError: VIDEO_SAVE_ERROR");
                        Log.e(TAG, "onError:"+message);
                    }
                }
        );
    }


    @SuppressLint("RestrictedApi")
    private void stopRecording() {
        videoCapture.stopRecording();
    }


    @SuppressLint("RestrictedApi")
    private void bindCameraUseCases() {
        //解绑
        cameraProvider.unbindAll();

        //绑定用例
        camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture, videoCapture);

        //预览
        preview.setSurfaceProvider(previewView.getSurfaceProvider());


    }

    private void initView() {
        previewView = mBinding.previewView;
        changeBtn = mBinding.change;
        recordView = mBinding.recordView;
    }

    private void showErrorToast(@NonNull String message) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
        } else {
            runOnUiThread(() -> Toast.makeText(this, message, Toast.LENGTH_SHORT).show());
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == PreviewActivity.REQ_PREVIEW && resultCode == RESULT_OK) {
            Intent intent = new Intent();
            intent.putExtra(RESULT_FILE_PATH, outputFilePath);
            intent.putExtra(RESULT_FILE_TYPE, !takingPicture);
            setResult(RESULT_OK, intent);
            finish();
        }
    }

    private void onFileSaved(File file) {
        outputFilePath = file.getAbsolutePath();
        String mimeType = takingPicture ? "image/jpeg" : "video/mp4";
        MediaScannerConnection.scanFile(this, new String[]{outputFilePath}, new String[]{mimeType}, null);
        PreviewActivity.startActivityForResult(this, outputFilePath, !takingPicture, "完成");
    }

    @Override
    protected void onDestroy() {
        cameraProvider.unbindAll();
        super.onDestroy();
    }
}

